home *** CD-ROM | disk | FTP | other *** search
/ Internet Info 1994 March / Internet Info CD-ROM (Walnut Creek) (March 1994).iso / networking / ip / ka9q / src.arc / DOMAIN.C < prev    next >
C/C++ Source or Header  |  1989-08-19  |  26KB  |  1,097 lines

  1. #include <stdio.h>
  2. #include <ctype.h>
  3. #include "global.h"
  4. #include "mbuf.h"
  5. #include "timer.h"
  6. #include "netuser.h"
  7. #include "socket.h"
  8. #include "cmdparse.h"
  9. #include "proc.h"
  10. #include "domain.h"
  11. #include "commands.h"
  12.  
  13. extern int errno;
  14.  
  15. static struct dserver *Dlist;        /* List of potential servers */
  16. static struct dserver *Dserver;        /* Current one being used */
  17. static char *Dsuffix;            /* Default suffix for names without periods */
  18. static int Dsocket;            /* Socket to use for domain queries */
  19. static struct proc *Drx;        /* Task ID of domain receiver */
  20. static int Ddebug = 0;
  21. static char *Dtypes[] = {
  22.     "",
  23.     "A",
  24.     "NS",
  25.     "MD",
  26.     "MF",
  27.     "CNAME",
  28.     "SOA",
  29.     "MB",
  30.     "MG",
  31.     "MR",
  32.     "NULL",
  33.     "WKS",
  34.     "PTR",
  35.     "HINFO",
  36.     "MINFO",
  37.     "MX",
  38.     "TXT"
  39. };
  40. static int Ndtypes = 17;
  41. static char delim[] = " \t\r\n";
  42. static struct {
  43.     char *name;
  44.     int32 address;
  45. } cache;
  46.  
  47. static void addit __ARGS((FILE *fp,struct rr *rrp1));
  48. static struct rr *dfind __ARGS((FILE *dbase,char *name,int type));
  49. static int dn_expand __ARGS((char *msg,char *eom,char *compressed,char *full,int fullen));
  50. static int doadds __ARGS((int argc,char *argv[],void *p));
  51. static int dodropds __ARGS((int argc,char *argv[],void *p));
  52. static int dosuffix __ARGS((int argc,char *argv[],void *p));
  53. static int dodtrace __ARGS((int argc,char *argv[],void *p));
  54. static void drx __ARGS((int unused, void *u,void *p));
  55. static struct dserver *dslookup __ARGS((int32 server));
  56. static void free_dhdr __ARGS((struct dhdr *dp));
  57. static void free_qu __ARGS((struct quest *qp));
  58. static void free_rr __ARGS((struct rr *rrp));
  59. static char *getq __ARGS((struct quest *qp,char *msg,char *cp));
  60. static struct rr *getrr __ARGS((FILE *fp));
  61. static int ntohdomain __ARGS((struct dhdr *dhdr,struct mbuf **bpp));
  62. static char *ntohrr __ARGS((struct rr *rrp,char *msg,char *cp));
  63. static void proc_answer __ARGS((struct dserver *dp,struct mbuf *bp));
  64. static void putrr __ARGS((FILE *fp,struct rr *rrp));
  65. static int res_mkquery __ARGS((int16 op,char *dname,int16 class,int16 type,
  66.     char *data,int16 datalen,int16 newrr,char *buffer,int16 buflen));
  67. static int rrcmp __ARGS((struct rr *rr1,struct rr *rr2));
  68.  
  69. static struct cmds Dcmds[] = {
  70.     "addserver",    doadds,        0, 0, NULLCHAR,
  71.     "dropserver",    dodropds,    0, 0, NULLCHAR,
  72.     "suffix",    dosuffix,    0, 0, NULLCHAR,
  73.     "trace",    dodtrace,    0, 0, NULLCHAR,
  74.     NULLCHAR,
  75. };
  76. int
  77. dodtrace(argc,argv,p)
  78. int argc;
  79. char *argv[];
  80. void *p;
  81. {
  82.     return setbool(&Ddebug,"Domain trace",argc,argv);
  83. }
  84. int
  85. dodomain(argc,argv,p)
  86. int argc;
  87. char *argv[];
  88. void *p;
  89. {
  90.     return subcmd(Dcmds,argc,argv,p);    
  91. }
  92. static int
  93. dosuffix(argc,argv,p)
  94. int argc;
  95. char *argv[];
  96. void *p;
  97. {
  98.     if(argc < 2){
  99.         if(Dsuffix != NULLCHAR)
  100.             printf("%s\n",Dsuffix);
  101.         return 0;
  102.     }
  103.     free(Dsuffix);
  104.     Dsuffix = strdup(argv[1]);
  105.     return 0;
  106. }
  107. static int
  108. doadds(argc,argv,p)
  109. int argc;
  110. char *argv[];
  111. void *p;
  112. {
  113.     struct dserver *dp;
  114.     int32 address;
  115.  
  116.     if((address = resolve(argv[1])) == 0){
  117.         printf("Resolver %s unknown\n",argv[1]);
  118.         return 1;
  119.     }
  120.     dp = (struct dserver *)calloc(1,sizeof(struct dserver));
  121.     dp->address = address;
  122.     dp->srtt = (5L * 1000) / MSPTICK; /* About 5 sec */
  123.     dp->timeout = dp->srtt * 2;
  124.     dp->mdev = 0;
  125.     dp->next = Dlist;
  126.     if(dp->next != NULLDOM)
  127.         dp->next->prev = dp;
  128.     Dlist = dp;
  129.     Dserver = dp;    /* Make this the first one we try next */
  130.     if(Drx == NULLPROC){
  131.         /* Start domain task upon first addserver */
  132.         Drx = newproc("Domain",1024,drx,0,NULL,NULL);
  133.     }
  134.     return 0;
  135. }
  136. static int
  137. dodropds(argc,argv,p)
  138. int argc;
  139. char *argv[];
  140. void *p;
  141. {
  142.     struct dserver *dp;
  143.     int32 addr;
  144.  
  145.     addr = resolve(argv[1]);
  146.     for(dp = Dlist;dp != NULLDOM;dp = dp->next)
  147.         if(addr == dp->address)
  148.             break;
  149.  
  150.     if(dp == NULLDOM){
  151.         printf("Not found\n");
  152.         return 1;
  153.     }
  154.     if(dp->prev != NULLDOM)
  155.         dp->prev->next = dp->next;
  156.     else
  157.         Dlist = dp->next;
  158.     if(dp->next != NULLDOM)
  159.         dp->next->prev = dp->prev;
  160.  
  161.     if(Dserver == dp)
  162.         Dserver = Dlist;
  163.     free((char *)dp);
  164.     return 0;
  165. }
  166.  
  167. /* Search local domain file for resource record of specified type.
  168.  * If a record is found, the domain file pointer is left just after it. If
  169.  * not, the file is rewound.
  170.  */
  171. static struct rr *
  172. dfind(dbase,name,type)
  173. FILE *dbase;
  174. char *name;
  175. int type;
  176. {
  177.     struct rr *rrp;
  178.     int nlen;
  179.  
  180.     /* Search file */
  181.     while((rrp = getrr(dbase)) != NULLRR){
  182.         if((nlen = strlen(name)) == strlen(rrp->name)
  183.          && strnicmp(name,rrp->name,nlen) == 0
  184.          && rrp->class == CLASS_IN
  185.          && rrp->type == type)
  186.             break;
  187.         free_rr(rrp);
  188.         pwait(NULL);    /* Give up CPU for a while, this is slow */
  189.     }
  190.     if(rrp == NULLRR)
  191.         rewind(dbase);
  192.     return rrp;
  193. }
  194. static struct rr *
  195. getrr(fp)
  196. FILE *fp;
  197. {
  198.     char *line,*strtok();
  199.     struct rr *rrp;
  200.     char *name,*ttl,*class,*type,*data;
  201.     int i;
  202.  
  203.     line = malloc(256);
  204.     /* Search file */
  205.     while(fgets(line,256,fp),!feof(fp)){
  206.         if(line[0] != '#')
  207.             break;
  208.     }
  209.     if(feof(fp) || (rrp = (struct rr *)calloc(1,sizeof(struct rr))) == NULLRR){
  210.         free(line);
  211.         return NULLRR;
  212.     }
  213.     name = strtok(line,delim);
  214.     ttl = strtok(NULLCHAR,delim);
  215.     class = strtok(NULLCHAR,delim);
  216.     type = strtok(NULLCHAR,delim);
  217.     data = strtok(NULLCHAR,delim);
  218.     
  219.     rrp->name = strdup(name);
  220.     if(!isdigit(ttl[0])){
  221.         /* Optional ttl field is missing; slide the other fields over */
  222.         data = type;
  223.         type = class;
  224.         class = ttl;
  225.         ttl = NULLCHAR;
  226.     } else {
  227.         rrp->ttl = atol(ttl);
  228.     }
  229.     for(i=0;i<NRLIST;i++){
  230.         if(strcmp(type,Dtypes[i]) == 0){
  231.             rrp->type = i;
  232.             break;
  233.         }
  234.     }
  235.     if(strcmp(class,"IN") == 0)
  236.         rrp->class = CLASS_IN;
  237.  
  238.     if(data == NULLCHAR){
  239.         /* Empty record, just return */
  240.         free(line);
  241.         return rrp;
  242.     }
  243.     switch(rrp->type){
  244.     case TYPE_CNAME:
  245.     case TYPE_MB:
  246.     case TYPE_MG:
  247.     case TYPE_MR:
  248.     case TYPE_NS:
  249.     case TYPE_PTR:
  250.     case TYPE_TXT:
  251.         rrp->rdlength = strlen(data);
  252.         rrp->rdata.name = strdup(data);
  253.         break;
  254.     case TYPE_A:
  255.         rrp->rdlength = 4;
  256.         rrp->rdata.addr = aton(data);
  257.         break;
  258.     case TYPE_HINFO:
  259.         rrp->rdlength = strlen(data);
  260.         rrp->rdata.hinfo.cpu = strdup(data);
  261.         if((data = strtok(NULLCHAR,delim)) != NULLCHAR){
  262.             rrp->rdlength += strlen(data);
  263.             rrp->rdata.hinfo.os = strdup(data);
  264.         }
  265.         break;
  266.     case TYPE_MX:
  267.         rrp->rdata.mx.pref = atoi(data);
  268.         rrp->rdlength = 2;
  269.  
  270.         /* Get domain name of exchanger */
  271.         if((data = strtok(NULLCHAR,delim)) != NULLCHAR){
  272.             rrp->rdlength += strlen(data);
  273.             rrp->rdata.mx.exch = strdup(data);
  274.         }
  275.         break;
  276.     case TYPE_SOA:
  277.         /* Get domain name of master name server */
  278.         rrp->rdlength = strlen(data);
  279.         rrp->rdata.soa.mname = strdup(data);
  280.  
  281.         /* Get domain name of irresponsible person */
  282.         if((data = strtok(NULLCHAR,delim)) != NULLCHAR){
  283.             rrp->rdata.soa.rname = strdup(data);
  284.             rrp->rdlength += strlen(data);
  285.         }
  286.         data = strtok(NULLCHAR,delim);
  287.         rrp->rdata.soa.serial = atol(data);
  288.         data = strtok(NULLCHAR,delim);
  289.         rrp->rdata.soa.refresh = atol(data);
  290.         data = strtok(NULLCHAR,delim);
  291.         rrp->rdata.soa.retry = atol(data);
  292.         data = strtok(NULLCHAR,delim);
  293.         rrp->rdata.soa.expire = atol(data);
  294.         data = strtok(NULLCHAR,delim);
  295.         rrp->rdata.soa.minimum = atol(data);
  296.         rrp->rdlength += 20;
  297.         break;
  298.     }
  299.     free(line);
  300.     return rrp;
  301. }
  302. /* Search for address record in local database, looking first for PTR
  303.  * and CNAME records. Return values:
  304.  *  0xffffffff    Not found (domain name may exist, but we don't know yet)
  305.  *  0        Domain name definitely doesn't exist (we have a null record)
  306.  */
  307. int32
  308. dresolve(name)
  309. char *name;
  310. {
  311.     register struct rr *rrp;
  312.     char *pname = NULLCHAR;
  313.     char *cname = NULLCHAR;
  314.     int32 result;
  315.     FILE *dbase;
  316.  
  317.     if(cache.name != NULLCHAR && strcmp(cache.name,name) == 0)
  318.         return cache.address;
  319.  
  320.     if((dbase = fopen(Dfile,READ_TEXT)) == NULLFILE)
  321.         return 0xffffffff;
  322.  
  323.     /* This code can handle a few weird cases. It works when there's
  324.      * a PTR to a CNAME to an A record, as well as when there's a
  325.      * a CNAME to a PTR to an A. But it allows only one of each kind
  326.      * of indirection to prevent infinite loops.
  327.      */
  328.     while((rrp = dfind(dbase,name,TYPE_A)) == NULLRR){
  329.         /* An address record didn't exist, let's see if it's an alias */
  330.         if(cname == NULLCHAR && (rrp = dfind(dbase,name,TYPE_CNAME)) != NULLRR){
  331.             if((cname = strdup(rrp->rdata.name)) == NULLCHAR)
  332.                 break;
  333.             name = cname;
  334.             rewind(dbase);
  335.             free_rr(rrp);
  336.             continue;    /* Try again */
  337.         }
  338.         /* Lacking that, try a pointer entry... */
  339.         if(pname == NULLCHAR && (rrp = dfind(dbase,name,TYPE_PTR)) != NULLRR){
  340.             if((pname = strdup(rrp->rdata.name)) == NULLCHAR)
  341.                 break;
  342.             name = pname;
  343.             rewind(dbase);
  344.             free_rr(rrp);
  345.             continue;
  346.         }
  347.         /* Nope, nothing. Give up */
  348.         break;
  349.     }
  350.     fclose(dbase);
  351.     free(pname);
  352.     free(cname);    
  353.  
  354.     if(rrp == NULLRR){
  355.         result = 0xffffffff;        /* No record in database */
  356.     } else {
  357.         if(rrp->rdlength == 0)
  358.             result = 0;        /* Negative response record */
  359.         else
  360.             result = rrp->rdata.addr;    /* Normal return */
  361.         free(cache.name);
  362.         cache.name = strdup(name);
  363.         cache.address = result;
  364.         free_rr(rrp);
  365.     }
  366.     return result;
  367. }
  368.  
  369. /* Main entry point for domain name -> address resolution. Returns 0 if
  370.  * name is definitely not valid.
  371.  */
  372. int32
  373. resolve(name)
  374. char *name;
  375. {
  376.     char *buf;
  377.     int32 addr;
  378.     struct dserver *dp;
  379.     int len;
  380.     struct sockaddr_in server;
  381.     char *tname = NULLCHAR;
  382.     char *pname = NULLCHAR;
  383.  
  384.     if(name == NULLCHAR)
  385.         return 0;
  386.  
  387.     if(*name == '[')
  388.         return aton(name + 1);
  389.  
  390.     if(strchr(name,'.') == NULLCHAR && Dsuffix != NULLCHAR){
  391.         /* Append default suffix */
  392.         tname = malloc(strlen(name)+strlen(Dsuffix)+2);
  393.         sprintf(tname,"%s.%s",name,Dsuffix);
  394.         name = tname;
  395.     }
  396.     if(name[strlen(name)-1] != '.'){
  397.         /* Append trailing dot */
  398.         pname = malloc(strlen(name)+2);
  399.         sprintf(pname,"%s.",name);
  400.         name = pname;
  401.     }
  402.     dp = Dserver;
  403.     while((addr = dresolve(name)) == 0xffffffff){
  404.         if(dp == NULLDOM){
  405.             addr = 0;    /* Unknown, and no servers */
  406.             break;
  407.         }
  408.         /* Not in file, send query */
  409.         buf = malloc(512);
  410.         len = res_mkquery(0,name,CLASS_IN,TYPE_A,NULLCHAR,0,0,buf,512);
  411.         server.sin_family = AF_INET;
  412.         server.sin_port = IPPORT_DOMAIN;
  413.         server.sin_addr.s_addr = dp->address;
  414.         sendto(Dsocket,buf,len,0,(char *)&server,sizeof(server));
  415.         free(buf);
  416.         alarm(dp->timeout);
  417.         /* Wait for something to happen */
  418.         len = pwait(&Dsocket);
  419.         alarm(0L);
  420.         switch(len){
  421.         case -1:
  422.             addr = 0;
  423.             goto quit;
  424.         case 0:
  425.             break;
  426.         case 1:
  427.             /* Timeout; back off this one and try another server */
  428.             dp->timeout <<= 1;
  429.             if((dp = dp->next) == NULLDOM)
  430.                 dp = Dlist;
  431.             break;
  432.         }
  433.     }
  434. quit:    free(tname);
  435.     free(pname);
  436.     return addr;
  437. }
  438. static int
  439. res_mkquery(op,dname,class,type,data,datalen,newrr,buffer,buflen)
  440. int16 op;    /* operation */
  441. char *dname;    /* Domain name */
  442. int16 class;    /* Class of inquiry (IN, etc) */
  443. int16 type;    /* Type of inquiry (A, MX, etc) */
  444. char *data;
  445. int16 datalen;
  446. int16 newrr;
  447. char *buffer;    /* Area for query */
  448. int16 buflen;    /* Length of same */
  449. {
  450.     char *cp,*cp1;
  451.     int16 parameter;
  452.     int16 dlen,len;
  453.  
  454.     cp = buffer;
  455.     cp = put16(cp,(int16)Clock);    /* Use clock for timestamping */
  456.     parameter = 0x100;    /* Recursion desired */
  457.     cp = put16(cp,parameter);
  458.     cp = put16(cp,1);
  459.     cp = put16(cp,0);
  460.     cp = put16(cp,0);
  461.     cp = put16(cp,0);
  462.     dlen = strlen(dname);
  463.     for(;;){
  464.         /* Look for next dot */
  465.         cp1 = strchr(dname,'.');
  466.         if(cp1 != NULLCHAR)
  467.             len = cp1-dname;    /* More to come */
  468.         else
  469.             len = dlen;    /* Last component */
  470.         *cp++ = len;        /* Write length of component */
  471.         if(len == 0)
  472.             break;
  473.         /* Copy component up to (but not including) dot */
  474.         strncpy(cp,dname,len);
  475.         cp += len;
  476.         if(cp1 == NULLCHAR){
  477.             *cp++ = 0;    /* Last one; write null and finish */
  478.             break;
  479.         }
  480.         dname += len+1;
  481.         dlen -= len+1;
  482.     }
  483.     cp = put16(cp,type);
  484.     cp = put16(cp,class);
  485.     return cp - buffer;
  486. }
  487. /* Convert a compressed domain name to the human-readable form */
  488. static int
  489. dn_expand(msg,eom,compressed,full,fullen)
  490. char *msg;        /* Complete domain message */
  491. char *eom;
  492. char *compressed;    /* Pointer to compressed name */
  493. char *full;        /* Pointer to result buffer */
  494. int fullen;        /* Length of same */
  495. {
  496.     unsigned int slen;    /* Length of current segment */
  497.     register char *cp;
  498.     unsigned int clen = 0;    /* Total length of compressed name */
  499.     int indirect = 0;    /* Set if indirection encountered */
  500.     int nseg = 0;        /* Total number of segments in name */
  501.  
  502.     cp = compressed;
  503.     for(;;){
  504.         slen = uchar(*cp++);    /* Length of this segment */
  505.         if(!indirect)
  506.             clen++;
  507.         if((slen & 0xc0) == 0xc0){
  508.             if(!indirect)
  509.                 clen++;
  510.             indirect = 1;
  511.             /* Follow indirection */
  512.             cp = &msg[((slen & 0x3f)<<8) + uchar(*cp)];
  513.             slen = uchar(*cp++);
  514.         }
  515.         if(slen == 0)    /* zero length == all done */
  516.             break;
  517.         fullen -= slen + 1;
  518.         if(fullen < 0)
  519.             return -1;
  520.         if(!indirect)
  521.             clen += slen;
  522.         while(slen-- != 0)
  523.             *full++ = *cp++;
  524.         *full++ = '.';
  525.         nseg++;
  526.     }
  527.     if(nseg == 0){
  528.         /* Root name; represent as single dot */
  529.         *full++ = '.';
  530.         fullen--;
  531.     }
  532.     *full++ = '\0';
  533.     fullen--;
  534.     return clen;    /* Length of compressed message */
  535. }
  536. /* Process to receive all domain server replies */
  537. static void
  538. drx()
  539. {
  540.     struct sockaddr_in sock,from;
  541.     int fromlen;
  542.     struct mbuf *bp;
  543.     struct dserver *dp,*dslookup();
  544.     int foo;
  545.  
  546.     Dsocket = socket(AF_INET,SOCK_DGRAM,0);
  547.     sock.sin_family = AF_INET;
  548.     sock.sin_addr.s_addr = Ip_addr;
  549.     sock.sin_port = IPPORT_DOMAIN;
  550.     if(bind(Dsocket,(char *)&sock,sizeof(sock)) == -1){
  551.         printf("Domain: can't bind (is ip address set?)\n");
  552.         Drx = NULLPROC;
  553.         return;
  554.     }
  555.     for(;;){
  556.         fromlen = sizeof(from);
  557.         foo = recv_mbuf(Dsocket,&bp,0,0,(char *)&from,&fromlen);
  558.         if(Ddebug)
  559.             printf("domain: %u bytes from %s\n",foo,
  560.              psocket((struct sockaddr *)&from));
  561.         if((dp = dslookup(from.sin_addr.s_addr)) == NULLDOM){
  562.             /* Unknown server */
  563.             if(Ddebug)
  564.                 printf("Unknown domain server!\n");
  565.             continue;
  566.         }
  567.         Dserver = dp;    /* We know this one is good */
  568.         proc_answer(dp,bp);
  569.     }
  570. }
  571. static void
  572. proc_answer(dp,bp)
  573. struct dserver *dp;
  574. struct mbuf *bp;
  575. {
  576.     FILE *fp;
  577.     struct dhdr dhdr;
  578.     int i;
  579.     int16 rtt;
  580.     long ttl = 500;    /* Default TTL for negative records without SOA */
  581.     struct rr *rrp;
  582.     struct quest *qp;
  583.  
  584.     ntohdomain(&dhdr,&bp);
  585.  
  586.     /* Compute and update the round trip time */
  587.     rtt = (int16)Clock - dhdr.id;
  588.     dp->srtt = (7 * dp->srtt + rtt) >> 3;
  589.     dp->timeout = 2*dp->srtt;
  590.  
  591.     if(Ddebug){
  592.         printf("response id %u (rtt %lu sec) qr %u opcode %u aa %u tc %u rd %u ra %u rcode %u\n",
  593.          dhdr.id,((long)rtt * MSPTICK)/1000,
  594.          dhdr.qr,dhdr.opcode,dhdr.aa,dhdr.tc,dhdr.rd,
  595.          dhdr.ra,dhdr.rcode);
  596.         printf("%u questions:\n",dhdr.qdcount);
  597.         for(i=0;i< dhdr.qdcount;i++){
  598.             qp = dhdr.qlist[i];
  599.             printf("%s type %u class %u\n",qp->qname,
  600.              qp->qtype,qp->qclass);
  601.         }
  602.     }
  603.     if(dhdr.qr == QUERY){
  604.         /* A server will eventually go here. */
  605.         free_dhdr(&dhdr);
  606.         return;
  607.     }
  608.     fp = fopen(Dfile,APPEND_TEXT);
  609.     if(fp == NULLFILE){
  610.         printf("Can't append to %s!!\n",Dfile);
  611.         free_dhdr(&dhdr);
  612.         return;
  613.     }
  614.     if(Ddebug)
  615.         printf("%u answers:\n",dhdr.ancount);
  616.     for(i=0;i< dhdr.ancount;i++){
  617.         rrp = dhdr.ans[i];
  618.         if(Ddebug)
  619.             putrr(stdout,rrp);
  620.         if(rrp->type == TYPE_SOA)
  621.             ttl = rrp->ttl;
  622.         addit(fp,rrp);
  623.     }
  624.     if(Ddebug)
  625.         printf("%u authority:\n",dhdr.nscount);
  626.     for(i=0;i< dhdr.nscount;i++){
  627.         rrp = dhdr.ns[i];
  628.         if(Ddebug){
  629.             putrr(stdout,rrp);
  630.             fflush(stdout);
  631.         }
  632.         if(rrp->type == TYPE_SOA)
  633.             ttl = rrp->ttl;
  634.         addit(fp,rrp);
  635.     }
  636.     if(Ddebug)
  637.         printf("%u additional:\n",dhdr.arcount);
  638.     for(i=0;i< dhdr.arcount;i++){
  639.         rrp = dhdr.add[i];
  640.         if(Ddebug){
  641.             putrr(stdout,rrp);
  642.             fflush(stdout);
  643.         }
  644.         if(rrp->type == TYPE_SOA)
  645.             ttl = rrp->ttl;
  646.         addit(fp,rrp);
  647.     }
  648.     if(dhdr.aa && (dhdr.rcode == NAME_ERROR || dhdr.ancount == 0)){
  649.         /* Add negative reply to file. This assumes that there was
  650.          * only one question, which is true for all questions we send.
  651.          */
  652.         qp = dhdr.qlist[0];
  653.         rrp = (struct rr *)calloc(1,sizeof(struct rr));
  654.         rrp->name = strdup(qp->qname);
  655.         rrp->type = qp->qtype;
  656.         rrp->class = qp->qclass;
  657.         rrp->ttl = ttl;
  658.         rrp->rdlength = 0;    /* no data */
  659.         addit(fp,rrp);
  660.         free_rr(rrp);
  661.     }
  662.     fclose(fp);
  663.     free_dhdr(&dhdr);
  664.     psignal(&Dsocket,0);    /* Alert anyone waiting for results */
  665. }
  666. static int
  667. ntohdomain(dhdr,bpp)
  668. struct dhdr *dhdr;
  669. struct mbuf **bpp;
  670. {
  671.     int16 tmp,len,i;
  672.     char *msg,*cp;
  673.  
  674.     len = len_mbuf(*bpp);
  675.     msg = malloc(len);
  676.     pullup(bpp,msg,len);
  677.     memset((char *)dhdr,0,sizeof(*dhdr));
  678.  
  679.         dhdr->id = get16(&msg[0]);
  680.     tmp = get16(&msg[2]);
  681.     if(tmp & 0x8000)
  682.         dhdr->qr = 1;
  683.     dhdr->opcode = (tmp >> 11) & 0xf;
  684.     if(tmp & 0x0400)
  685.         dhdr->aa = 1;
  686.     if(tmp & 0x0200)
  687.         dhdr->tc = 1;
  688.     if(tmp & 0x0100)
  689.         dhdr->rd = 1;
  690.     if(tmp & 0x0080)
  691.         dhdr->ra = 1;
  692.     dhdr->rcode = tmp & 0xf;
  693.     dhdr->qdcount = get16(&msg[4]);
  694.     dhdr->ancount = get16(&msg[6]);
  695.     dhdr->nscount = get16(&msg[8]);
  696.     dhdr->arcount = get16(&msg[10]);
  697.  
  698.     /* Now parse the variable length sections */
  699.     cp = &msg[12];
  700.  
  701.     /* Question section */
  702.     if(dhdr->qdcount != 0)
  703.         dhdr->qlist = (struct quest **)malloc(dhdr->qdcount *
  704.          sizeof(struct quest *));
  705.     for(i=0;i<dhdr->qdcount;i++){
  706.         dhdr->qlist[i] = (struct quest *)malloc(sizeof(struct quest));
  707.         if((cp = getq(dhdr->qlist[i],msg,cp)) == NULLCHAR){
  708.             free(msg);
  709.             return -1;
  710.         }
  711.     }
  712.     /* Answer section */
  713.     if(dhdr->ancount != 0)
  714.         dhdr->ans = (struct rr **)malloc(dhdr->ancount *
  715.          sizeof(struct rr *));
  716.     for(i=0;i<dhdr->ancount;i++){
  717.         dhdr->ans[i] = (struct rr *)malloc(sizeof(struct rr));
  718.         if((cp = ntohrr(dhdr->ans[i],msg,cp)) == NULLCHAR){
  719.             free(msg);
  720.             return -1;
  721.         }
  722.     }        
  723.     /* Name server (authority) section */
  724.     if(dhdr->nscount != 0)
  725.         dhdr->ns = (struct rr **)malloc(dhdr->nscount *
  726.          sizeof(struct rr *));
  727.     for(i=0;i<dhdr->nscount;i++){
  728.         dhdr->ns[i] = (struct rr *)malloc(sizeof(struct rr));
  729.         if((cp = ntohrr(dhdr->ns[i],msg,cp)) == NULLCHAR){
  730.             free(msg);
  731.             return -1;
  732.         }
  733.     }
  734.     /* Additional section */
  735.     if(dhdr->arcount != 0)
  736.         dhdr->add = (struct rr **)malloc(dhdr->arcount *
  737.          sizeof(struct rr *));
  738.     for(i=0;i<dhdr->arcount;i++){
  739.         dhdr->add[i] = (struct rr *)malloc(sizeof(struct rr));
  740.         if((cp = ntohrr(dhdr->add[i],msg,cp)) == NULLCHAR){
  741.             free(msg);
  742.             return -1;
  743.         }
  744.     }
  745.     free(msg);
  746.     return 0;
  747. }
  748. static char *
  749. getq(qp,msg,cp)
  750. struct quest *qp;
  751. char *msg;
  752. char *cp;
  753. {
  754.     int len;
  755.     char *name;
  756.  
  757.     name = malloc(512);
  758.     len = dn_expand(msg,NULLCHAR,cp,name,512);
  759.     if(len == -1){
  760.         free(name);
  761.         return NULLCHAR;
  762.     }
  763.     cp += len;
  764.     qp->qname = strdup(name);
  765.     qp->qtype = get16(cp);
  766.     cp += 2;
  767.     qp->qclass = get16(cp);
  768.     cp += 2;
  769.     free(name);
  770.     return cp;
  771. }
  772. /* Read a resource record from a domain message into a host structure */
  773. static char *
  774. ntohrr(rrp,msg,cp)
  775. struct rr *rrp;    /* Pointer to allocated resource record structure */
  776. char *msg;    /* Pointer to beginning of domain message */
  777. char *cp;    /* Pointer to start of encoded RR record */
  778. {
  779.     int len;
  780.     char *name;
  781.  
  782.     if((name = malloc(512)) == NULLCHAR)
  783.         return NULLCHAR;
  784.     if((len = dn_expand(msg,NULLCHAR,cp,name,512)) == -1){
  785.         free(name);
  786.         return NULLCHAR;
  787.     }
  788.     cp += len;
  789.     rrp->name = strdup(name);
  790.     rrp->type = get16(cp);
  791.     cp += 2;
  792.     rrp->class = get16(cp);
  793.     cp+= 2;
  794.     rrp->ttl = get32(cp);
  795.     cp += 4;
  796.     rrp->rdlength = get16(cp);
  797.     cp += 2;
  798.     switch(rrp->type){
  799.     case TYPE_CNAME:
  800.     case TYPE_MB:
  801.     case TYPE_MG:
  802.     case TYPE_MR:
  803.     case TYPE_NS:
  804.     case TYPE_PTR:
  805.         /* These types all consist of a single domain name;
  806.          * convert it to ascii format
  807.          */
  808.         len = dn_expand(msg,NULLCHAR,cp,name,512);
  809.         if(len == -1){
  810.             free(name);
  811.             return NULLCHAR;
  812.         }
  813.         rrp->rdata.name = strdup(name);
  814.         cp += len;
  815.         break;
  816.     case TYPE_A:
  817.         /* Just read the address directly into the structure */
  818.         rrp->rdata.addr = get32(cp);
  819.         cp += 4;
  820.         break;
  821.     case TYPE_HINFO:
  822.         rrp->rdata.hinfo.cpu = strdup(cp);
  823.         cp += strlen(cp) + 1;
  824.  
  825.         rrp->rdata.hinfo.os = strdup(cp);
  826.         cp += strlen(cp) + 1;
  827.         break;
  828.     case TYPE_MX:
  829.         rrp->rdata.mx.pref = get16(cp);
  830.         cp += 2;
  831.         /* Get domain name of exchanger */
  832.         len = dn_expand(msg,NULLCHAR,cp,name,512);
  833.         if(len == -1){
  834.             free(name);
  835.             return NULLCHAR;
  836.         }
  837.         rrp->rdata.mx.exch = strdup(name);
  838.         cp += len;
  839.         break;
  840.     case TYPE_SOA:
  841.         /* Get domain name of name server */
  842.         len = dn_expand(msg,NULLCHAR,cp,name,512);
  843.         if(len == -1){
  844.             free(name);
  845.             return NULLCHAR;
  846.         }
  847.         rrp->rdata.soa.mname = strdup(name);
  848.         cp += len;
  849.  
  850.         /* Get domain name of responsible person */
  851.         len = dn_expand(msg,NULLCHAR,cp,name,512);
  852.         if(len == -1){
  853.             free(name);
  854.             return NULLCHAR;
  855.         }
  856.         rrp->rdata.soa.rname = strdup(name);
  857.         cp += len;
  858.  
  859.         rrp->rdata.soa.serial = get32(cp);
  860.         cp += 4;
  861.         rrp->rdata.soa.refresh = get32(cp);
  862.         cp += 4;
  863.         rrp->rdata.soa.retry = get32(cp);
  864.         cp += 4;
  865.         rrp->rdata.soa.expire = get32(cp);
  866.         cp += 4;
  867.         rrp->rdata.soa.minimum = get32(cp);
  868.         cp += 4;
  869.         break;
  870.     case TYPE_TXT:
  871.         /* Just stash */
  872.         rrp->rdata.data = malloc(rrp->rdlength);
  873.         memcpy(rrp->rdata.data,cp,rrp->rdlength);
  874.         cp += rrp->rdlength;
  875.         break;
  876.     default:
  877.         /* Ignore */
  878.         cp += rrp->rdlength;
  879.         break;
  880.     }
  881.     free(name);
  882.     return cp;
  883. }
  884. /* Print a resource record */
  885. static void
  886. putrr(fp,rrp)
  887. FILE *fp;
  888. struct rr *rrp;
  889. {
  890.     if(fp == NULLFILE || rrp == NULLRR)
  891.         return;
  892.  
  893.     fprintf(fp,"%s\t%lu",rrp->name,rrp->ttl);
  894.     if(rrp->class == CLASS_IN)
  895.         fprintf(fp,"\tIN");
  896.     else
  897.         fprintf(fp,"\t%u",rrp->class);
  898.     if(rrp->type < Ndtypes)
  899.         fprintf(fp,"\t%s",Dtypes[rrp->type]);
  900.     else
  901.         fprintf(fp,"\t%u",rrp->type);
  902.     if(rrp->rdlength == 0){
  903.         /* Null data portion, indicates nonexistent record */
  904.         fprintf(fp,"\n");
  905.         return;
  906.     }
  907.     switch(rrp->type){
  908.     case TYPE_CNAME:
  909.     case TYPE_MB:
  910.     case TYPE_MG:
  911.     case TYPE_MR:
  912.     case TYPE_NS:
  913.     case TYPE_PTR:
  914.     case TYPE_TXT:
  915.         /* These are all printable text strings */
  916.         fprintf(fp,"\t%s\n",rrp->rdata.data);
  917.         break;
  918.     case TYPE_A:
  919.         fprintf(fp,"\t%s\n",inet_ntoa(rrp->rdata.addr));
  920.         break;
  921.     case TYPE_MX:
  922.         fprintf(fp,"\t%u\t%s\n",rrp->rdata.mx.pref,
  923.          rrp->rdata.mx.exch);
  924.         break;
  925.     case TYPE_SOA:
  926.         fprintf(fp,"\t%s\t%s\t%lu\t%lu\t%lu\t%lu\t%lu\n",
  927.          rrp->rdata.soa.mname,rrp->rdata.soa.rname,
  928.          rrp->rdata.soa.serial,rrp->rdata.soa.refresh,
  929.          rrp->rdata.soa.retry,rrp->rdata.soa.expire,
  930.          rrp->rdata.soa.minimum);
  931.         break;
  932.     default:
  933.         fprintf(fp,"\n");
  934.         break;
  935.     }
  936. }
  937. /* Add a record to the database only if it doesn't already exist */
  938. static void
  939. addit(fp,rrp1)
  940. FILE *fp;
  941. struct rr *rrp1;
  942. {
  943.     register struct rr *rrp;
  944.  
  945.     rewind(fp);
  946.     while((rrp = dfind(fp,rrp1->name,rrp1->type)) != NULLRR){
  947.         if(rrcmp(rrp,rrp1) == 0){
  948.             free_rr(rrp);
  949.             return;
  950.         }
  951.         free_rr(rrp);
  952.     }
  953.     fseek(fp,0L,2);
  954.     putrr(fp,rrp1);
  955. }
  956. static struct dserver *
  957. dslookup(server)
  958. int32 server;
  959. {
  960.     struct dserver *dp;
  961.  
  962.     for(dp = Dlist;dp != NULLDOM;dp = dp->next)
  963.         if(dp->address == server)
  964.             break;
  965.     return dp;
  966. }
  967. /* Free a domain message */
  968. static void
  969. free_dhdr(dp)
  970. struct dhdr *dp;
  971. {
  972.     int i;
  973.  
  974.     if(dp->qdcount != 0){
  975.         for(i=0;i<dp->qdcount;i++)
  976.             free_qu(dp->qlist[i]);
  977.         free((char *)dp->qlist);
  978.     }
  979.     if(dp->ancount != 0){
  980.         for(i=0;i<dp->ancount;i++)
  981.             free_rr(dp->ans[i]);
  982.         free((char *)dp->ans);
  983.     }
  984.     if(dp->nscount != 0){
  985.         for(i=0;i<dp->nscount;i++)
  986.             free_rr(dp->ns[i]);
  987.         free((char *)dp->ns);
  988.     }
  989.     if(dp->arcount != 0){
  990.         for(i=0;i<dp->arcount;i++)
  991.             free_rr(dp->add[i]);
  992.         free((char *)dp->add);
  993.     }
  994. }
  995.  
  996. /* Free a question record */
  997. static void
  998. free_qu(qp)
  999. struct quest *qp;
  1000. {
  1001.     free(qp->qname);
  1002.     free((char *)qp);
  1003. }
  1004.  
  1005. /* Free a resource record */
  1006. static void
  1007. free_rr(rrp)
  1008. struct rr *rrp;
  1009. {
  1010.     if(rrp == NULLRR)
  1011.         return;
  1012.     free(rrp->name);
  1013.     if(rrp->rdlength != 0){
  1014.         switch(rrp->type){
  1015.         case TYPE_CNAME:
  1016.         case TYPE_MB:
  1017.         case TYPE_MG:
  1018.         case TYPE_MR:
  1019.         case TYPE_NS:
  1020.         case TYPE_PTR:
  1021.             free(rrp->rdata.name);
  1022.             break;
  1023.         case TYPE_A:
  1024.             break;    /* Nothing allocated in rdata section */
  1025.         case TYPE_HINFO:
  1026.             free(rrp->rdata.hinfo.cpu);
  1027.             free(rrp->rdata.hinfo.os);
  1028.             break;
  1029.         case TYPE_MX:
  1030.             free(rrp->rdata.mx.exch);
  1031.             break;
  1032.         case TYPE_SOA:
  1033.             free(rrp->rdata.soa.mname);
  1034.             free(rrp->rdata.soa.rname);
  1035.             break;
  1036.         case TYPE_TXT:
  1037.             free(rrp->rdata.data);
  1038.             break;
  1039.         }
  1040.     }
  1041.     free((char *)rrp);
  1042. }
  1043. /* Compare two resource records, returning 0 if equal, nonzero otherwise */
  1044. static int
  1045. rrcmp(rr1,rr2)
  1046. register struct rr *rr1,*rr2;
  1047. {
  1048.     int i;
  1049.  
  1050.     if(rr1 == NULLRR || rr2 == NULLRR)
  1051.         return -1;
  1052.     if((i = strlen(rr1->name)) != strlen(rr2->name))
  1053.         return 1;
  1054.     if((i = strnicmp(rr1->name,rr2->name,i)) != 0)
  1055.         return i;
  1056.     if(rr1->type != rr2->type)
  1057.         return 2;
  1058.     if(rr1->class != rr2->class)
  1059.         return 3;
  1060.     /* Note: rdlengths are not compared because they vary depending
  1061.      * on the representation (ASCII or encoded) this record was
  1062.      * generated from.
  1063.      */
  1064.     switch(rr1->type){
  1065.     case TYPE_A:
  1066.         i = rr1->rdata.addr != rr2->rdata.addr;
  1067.         break;
  1068.     case TYPE_SOA:
  1069.         i = rr1->rdata.soa.serial != rr2->rdata.soa.serial;
  1070.         break;
  1071.     case TYPE_HINFO:
  1072.         i = strcmp(rr1->rdata.hinfo.cpu,rr2->rdata.hinfo.cpu) ||
  1073.             strcmp(rr1->rdata.hinfo.os,rr2->rdata.hinfo.os);
  1074.         break;
  1075.     case TYPE_MX:
  1076.         i = strcmp(rr1->rdata.mx.exch,rr2->rdata.mx.exch);
  1077.         break;
  1078.     case TYPE_MB:
  1079.     case TYPE_MG:
  1080.     case TYPE_MR:
  1081.     case TYPE_NULL:
  1082.     case TYPE_WKS:
  1083.     case TYPE_PTR:
  1084.     case TYPE_MINFO:
  1085.     case TYPE_TXT:
  1086.     case TYPE_NS:
  1087.         i = strcmp(rr1->rdata.data,rr2->rdata.data);
  1088.         break;
  1089.     case TYPE_MD:
  1090.     case TYPE_MF:
  1091.     case TYPE_CNAME:
  1092.         i = strcmp(rr1->rdata.data,rr2->rdata.data);
  1093.         break;
  1094.     }
  1095.     return i;
  1096. }
  1097.